using Assimp;
using OpenTK.Graphics.OpenGL4;
using System.Collections.Generic;

namespace _3Dto2D.Services;

public class ModelRenderer : IDisposable
{
    private class MeshRenderInfo
    {
        public MeshRenderer Renderer { get; }
        public Texture? Texture { get; set; }
        public Assimp.Color4D DiffuseColor { get; set; }

        public MeshRenderInfo(MeshRenderer renderer)
        {
            Renderer = renderer;
            DiffuseColor = new Assimp.Color4D(1.0f, 1.0f, 1.0f, 1.0f); // Default to white
        }
    }

    private readonly List<MeshRenderInfo> _meshRenderInfos = new List<MeshRenderInfo>();
    private readonly string _directory;

    public ModelRenderer(string path)
    {
        _directory = Path.GetDirectoryName(path) ?? string.Empty;

        var assimpContext = new AssimpContext();
        var scene = assimpContext.ImportFile(path, PostProcessSteps.Triangulate | PostProcessSteps.FlipUVs);

        if (scene == null || scene.RootNode == null || scene.SceneFlags.HasFlag(SceneFlags.Incomplete))
        {
            throw new Exception($"Failed to load model: {path}");
        }

        ProcessNode(scene.RootNode, scene);
    }

    private void ProcessNode(Node node, Scene scene)
    {
        foreach (var meshIndex in node.MeshIndices)
        {
            var mesh = scene.Meshes[meshIndex];
            var meshRenderInfo = new MeshRenderInfo(new MeshRenderer(mesh));

            if (mesh.MaterialIndex >= 0)
            {
                var material = scene.Materials[mesh.MaterialIndex];
                if (material.HasTextureDiffuse)
                {
                    var texturePath = material.TextureDiffuse.FilePath;
                    meshRenderInfo.Texture = new Texture(Path.Combine(_directory, texturePath));
                }

                if (material.HasColorDiffuse)
                {
                    meshRenderInfo.DiffuseColor = material.ColorDiffuse;
                }
            }

            _meshRenderInfos.Add(meshRenderInfo);
        }

        foreach (var child in node.Children)
        {
            ProcessNode(child, scene);
        }
    }

    public void Render(Shader shader)
    {
        foreach (var info in _meshRenderInfos)
        {
            info.Texture?.Bind();
            shader.SetUniform("uDiffuseColor", new OpenTK.Mathematics.Vector4(info.DiffuseColor.R, info.DiffuseColor.G, info.DiffuseColor.B, info.DiffuseColor.A));
            info.Renderer.Render();
        }
    }

    public void Dispose()
    {
        foreach (var info in _meshRenderInfos)
        {
            info.Renderer.Dispose();
            info.Texture?.Dispose();
        }
    }
}
